package com.rxnetwork.manager


import com.google.gson.Gson
import okhttp3.Cache
import okhttp3.Interceptor
import okhttp3.MediaType
import okhttp3.OkHttpClient
import retrofit2.CallAdapter
import retrofit2.Converter
import retrofit2.Retrofit
import retrofit2.adapter.rxjava.RxJavaCallAdapterFactory
import retrofit2.converter.gson.GsonConverterFactory
import rx.Observable
import rx.Subscriber
import rx.Subscription
import rx.android.schedulers.AndroidSchedulers
import rx.schedulers.Schedulers
import rx.subscriptions.CompositeSubscription
import java.util.concurrent.TimeUnit

class RxNetWork private constructor() {
    private var timeout_time = 15
    private var isRetryOnConnectionFailure = true
    private var mGson: Gson? = null
    private var baseUrl: String? = null
    private var mOkHttpClient: OkHttpClient? = null
    private var mConverterFactory: Converter.Factory? = null
    private var mAdapterFactory: CallAdapter.Factory? = null

    private var mLogInterceptor: Interceptor? = null
    private var mHeaderInterceptor: Interceptor? = null
    private var mCacheInterceptor: Interceptor? = null
    private var mCache: Cache? = null
    private var compositeSubscription: CompositeSubscription? = null

    private object RxNetWorkHolder {

        val rxNetWork = RxNetWork()
    }

    fun setRetryOnConnectionFailure(retryOnConnectionFailure: Boolean): RxNetWork {
        isRetryOnConnectionFailure = retryOnConnectionFailure
        return this
    }

    fun setBaseUrl(url: String): RxNetWork {
        this.baseUrl = url
        return this
    }

    fun setGson(gson: Gson): RxNetWork {
        this.mGson = gson
        return this
    }

    fun setOkHttpClient(okHttpClient: OkHttpClient): RxNetWork {
        this.mOkHttpClient = okHttpClient
        return this
    }

    fun setLogInterceptor(mLogInterceptor: Interceptor): RxNetWork {
        this.mLogInterceptor = mLogInterceptor
        return this
    }

    fun setHeaderInterceptor(mHeaderInterceptor: Interceptor): RxNetWork {
        this.mHeaderInterceptor = mHeaderInterceptor
        return this
    }

    fun setCacheInterceptor(mCacheInterceptor: Interceptor): RxNetWork {
        this.mCacheInterceptor = mCacheInterceptor
        return this
    }

    fun setCache(mCache: Cache): RxNetWork {
        this.mCache = mCache
        return this
    }

    fun setTimeoutTime(timeout_time: Int): RxNetWork {
        this.timeout_time = timeout_time
        return this
    }

    fun setConverterFactory(factory: Converter.Factory): RxNetWork {
        this.mConverterFactory = factory
        return this

    }

    fun setAdapterFactory(factory: CallAdapter.Factory): RxNetWork {
        this.mAdapterFactory = factory
        return this
    }

    /**
     * 取消所有网络
     */
    fun clearSubscription() {
        if (compositeSubscription != null && !(compositeSubscription?.isUnsubscribed as Boolean)) {
            compositeSubscription?.clear()
        }
    }

    /**
     * 取消单个网络
     */
    fun clearSubscription(subscription: Subscription) {
        if (compositeSubscription != null && !(compositeSubscription?.isUnsubscribed as Boolean)) {
            subscription.unsubscribe()
        }
    }

    /**
     * 全状态回调

     * @param observable
     * *
     * @param listener
     * *
     * @param <M>
    </M> */
    fun <M> getApi(observable: Observable<M>, listener: RxNetWorkFullListener<M>) {
        compositeSubscription = CompositeSubscription()
        listener.onNetWorkStart()
        val subscribe = observable
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(object : Subscriber<M>() {
                    override fun onCompleted() {
                        listener.onNetWorkCompleted()
                    }

                    override fun onError(e: Throwable) {
                        listener.onNetWorkError(e)
                    }

                    override fun onNext(m: M) {
                        listener.onNetWorkSuccess(m)
                    }
                })
        compositeSubscription?.add(subscribe)
    }

    /**
     * 成功和失败回调

     * @param observable
     * *
     * @param listener
     * *
     * @param <M>
    </M> */
    fun <M> getApi(observable: Observable<M>, listener: RxNetWorkListener<M>) {
        compositeSubscription = CompositeSubscription()
        val subscribe = observable
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(object : Subscriber<M>() {
                    override fun onCompleted() {}

                    override fun onError(e: Throwable) {
                        listener.onNetWorkError(e)
                    }

                    override fun onNext(m: M) {
                        listener.onNetWorkSuccess(m)
                    }
                })
        compositeSubscription?.add(subscribe)
    }

    val retrofit: Retrofit
        get() {
            if (mOkHttpClient == null) {
                mOkHttpClient = initOkHttp()
            }
            if (mConverterFactory == null) {
                rxNetWorkConverterFactory()
            }
            if (mAdapterFactory == null) {
                rxNetWorkAdapterFactory()
            }
            return Retrofit.Builder()
                    ?.client(mOkHttpClient)
                    ?.baseUrl(baseUrl)
                    ?.addConverterFactory(mConverterFactory)
                    ?.addCallAdapterFactory(mAdapterFactory)
                    ?.build() as Retrofit
        }

    private fun initOkHttp(): OkHttpClient {
        val builder = OkHttpClient.Builder()
        if (mLogInterceptor != null)
            builder.addInterceptor(mLogInterceptor)
        if (mHeaderInterceptor != null)
            builder.addInterceptor(mHeaderInterceptor)
        if (mCacheInterceptor != null && mCache != null) {
            builder.cache(mCache)
            builder.addNetworkInterceptor(mCacheInterceptor)
            builder.addInterceptor(mCacheInterceptor)
        }
        builder.connectTimeout(timeout_time.toLong(), TimeUnit.SECONDS)
                .writeTimeout(timeout_time.toLong(), TimeUnit.SECONDS)
                .readTimeout(timeout_time.toLong(), TimeUnit.SECONDS)
        builder.retryOnConnectionFailure(isRetryOnConnectionFailure)
        return builder.build()
    }

    private fun rxNetWorkConverterFactory() {
        if (mGson == null) {
            mGson = Gson()
        }
        mConverterFactory = GsonConverterFactory.create(mGson)
    }

    private fun rxNetWorkAdapterFactory() {
        mAdapterFactory = RxJavaCallAdapterFactory.create()
    }

    companion object {

        val instance: RxNetWork
            get() = RxNetWorkHolder.rxNetWork

        fun <T> observable(service: Class<T>): T {
            return instance.retrofit.create(service)
        }

        private val MEDIA_TYPE_PNG = MediaType.parse("image/png")
    }

}
